package main

import (
	"fmt"
	"io"
	"log"
	"net/http"
	"os"

	"bytes"
	"github.com/aliyun/aliyun-ccp/ccppath-sdk/go/client"
	yaml2 "gopkg.in/yaml.v3"
	"io/ioutil"
	"mime/multipart"
	"strings"
)

func uploadFile(w http.ResponseWriter, r *http.Request) {
	if r.Method == "GET" {
		w.Header().Add("Content-Type", "text/html")
		w.WriteHeader(200)
		html := `
<form enctype="multipart/form-data" action="/upload" method="POST">
	上传文件: <input name="file" type="file" />
	<input type="submit" value="点击上传" />
</form>
`
		io.WriteString(w, html)
	}
	if r.Method == "POST" {
		file, header, err := r.FormFile("file")
		if err != nil {
			http.Error(w, err.Error(), 500)
			return
		}
		defer file.Close()
		_, err = os.Stat("./upload")
		if err != nil {
			if os.IsNotExist(err) {
				os.MkdirAll("./upload", 0766)
			}
		}
		destFile, err := os.Create("./upload/" + header.Filename)
		if err != nil {
			http.Error(w, err.Error(), 500)
			return
		}
		defer destFile.Close()
		_, err = io.Copy(destFile, file)
		if err != nil {
			http.Error(w, err.Error(), 500)
			return
		}
		//开始上传
		var f FileInfo
		f.FilePath = "./upload/" + header.Filename
		f.FileName = header.Filename
		err = createCcpFile(f)
		if err != nil {
			log.Println(err.Error())
		}
		fmt.Println("上传成功")
		w.Write([]byte("上传成功"))
	}
}

//上传ccp
func createCcpFile(fileInfo FileInfo) (err error) {
	cfq := new(client.CCPCreateFileRequest).
		SetDriveId("1").
		SetName(fileInfo.FileName).
		SetType("file").
		SetParentFileId("root").
		SetContentType("text/plain")
	cfqm := new(client.CCPCreateFileRequestModel).SetBody(cfq)
	response, err := ccpClient.CreateFile(cfqm, runtime)
	if err != nil {
		fmt.Println(err.Error())
		return
	}
	var uploadUrl, uploadId, FileId *string
	if response != nil {
		uploadUrl = response.Body.PartInfoList[0].UploadUrl
		uploadId = response.Body.UploadId
		FileId = response.Body.FileId
		// upload file
		// 此处可以使用os.Open()上传本地文件， 具体使用请参考os package。
		fmt.Println("******************upload file******************")
		//file := httpup()
		file, _ := ioutil.ReadFile(fileInfo.FilePath)
		content := strings.NewReader(string(file))
		req, _ := http.NewRequest("PUT", *uploadUrl, content)
		req.Header.Add("Content-Type", "")
		res, _ := http.DefaultClient.Do(req)
		Etag := res.Header.Get("ETag")
		uploadPartInfo := new(client.UploadPartInfo)
		uploadPartInfo.SetEtag(Etag)
		uploadPartInfo.SetPartNumber(1)
		// complete file
		fmt.Println("******************complete file******************")
		completeFileRequest := new(client.CCPCompleteFileRequest).
			SetDriveId("1").
			SetFileId(*FileId).
			SetUploadId(*uploadId).
			SetPartInfoList([]*client.UploadPartInfo{uploadPartInfo})
		cfrm := new(client.CCPCompleteFileRequestModel).SetBody(completeFileRequest)
		completeResponse, completeErr := ccpClient.CompleteFile(cfrm, runtime)
		if completeErr != nil {
			fmt.Println(completeErr.Error())
			return err
		}
		fmt.Println(completeResponse)
		return nil
	}
	return nil
}

type CompleteFileInfo struct {
	FileId string
	Name   string
}

//file列表
func listFile() {
	listFileReq := new(client.CCPListFileRequest).
		SetDriveId("1").
		SetParentFileId("root").
		SetLimit(10)
	lfrm := new(client.CCPListFileRequestModel).SetBody(listFileReq)
	listFileRes, err := ccpClient.ListFile(lfrm, runtime)
	if err != nil {
		fmt.Println(err.Error())
	}
	fmt.Println(listFileRes)
}

func downloadFile(w http.ResponseWriter, r *http.Request) {
	keys, ok := r.URL.Query()["fid"]
	if !ok || len(keys) < 1 {
		log.Println("请传入fid")
		w.Write([]byte("请传入fid"))
		return
	}
	fileUrl, err := getDownloadUrl(keys[0])
	if err != nil {
		w.Write([]byte("file is not exist"))
		return
	}
	res, _ := http.Get(*fileUrl)
	_, err = os.Stat("./down")
	if err != nil {
		if os.IsNotExist(err) {
			os.MkdirAll("./down", 0766)
		}
	}
	ext := strings.Split(*fileUrl, ".")
	fp := "./down/" + keys[0] + "." + ext[len(ext)-1]
	f, _ := os.Create(fp)
	io.Copy(f, res.Body)
	defer f.Close()

	of, _ := os.Open(fp)
	b, err := ioutil.ReadAll(of)
	w.Header().Set("Content-Disposition", "attachment; filename="+keys[0]+"."+ext[len(ext)-1])
	w.Write(b)
}

//获取下载地址
func getDownloadUrl(fileId string) (url *string, err error) {
	getDownloadRequest := new(client.CCPGetDownloadUrlRequest).
		SetDriveId("1").
		SetFileId(fileId)
	gdrm := new(client.CCPGetDownloadUrlRequestModel).SetBody(getDownloadRequest)
	getdownloadResponse, err := ccpClient.GetDownloadUrl(gdrm, runtime)
	if err != nil {
		fmt.Println(err.Error())
		return nil, err
	}
	url = getdownloadResponse.Body.Url
	return url, nil
}

//查询File
func searcFile() {
	searchFileReq := new(client.CCPSearchFileRequest).
		SetDriveId("1").
		SetLimit(10).
		SetOrderBy("type DESC").
		SetQuery("file_extension in ['txt']")
	sfrm := new(client.CCPSearchFileRequestModel).SetBody(searchFileReq)
	searchFileRes, err := ccpClient.SearchFile(sfrm, runtime)
	if err != nil {
		fmt.Println(err.Error())
	}
	fmt.Println(searchFileRes)
}

type Conf struct {
	ACCESS_KEY_ID     string `yaml:"access_id"`
	ACCESS_KEY_SECRET string `yaml:"access_secret"`
	DOMAIN_ID         string `yaml:"domain_id"`
}

type FileInfo struct {
	FileName string
	FilePath string
}

func (c *Conf) GetConf() *Conf {
	yaml, err := ioutil.ReadFile("conf.yaml")
	if err != nil {
		log.Println(err)
	}
	err = yaml2.Unmarshal(yaml, c)
	if err != nil {
		log.Println(err)
	}
	return c
}

var c Conf
var conf = c.GetConf()
var ossConfig = new(client.Config).
	SetDomainId(conf.DOMAIN_ID).
	SetProtocol("https").
	SetAccessKeyId(conf.ACCESS_KEY_ID).
	SetAccessKeySecret(conf.ACCESS_KEY_SECRET)
var runtime = &client.RuntimeOptions{}
var ccpClient, _ = client.NewClient(ossConfig)

func createFilen() {
	createFileRequest := new(client.CCPCreateFileRequest).
		SetDriveId("1").
		SetName("G:\\360Downloads\\code\\gocode\\codebak\\elastic_demo\\alisdk\\client\\client.go").
		SetType("file").
		SetParentFileId("root").
		SetContentType("text/plain")
	cfrm := new(client.CCPCreateFileRequestModel).SetBody(createFileRequest)
	response, err := ccpClient.CreateFile(cfrm, runtime)
	if err != nil {
		fmt.Println(err.Error())
		return
	}
	if response != nil {
		fmt.Println(response)
	}
}

func httpup() string {
	bodyBuffer := &bytes.Buffer{}
	bodyWriter := multipart.NewWriter(bodyBuffer)

	fileWriter, _ := bodyWriter.CreateFormFile("files", "G:\\360Downloads\\code\\gocode\\codebak\\elastic_demo\\alisdk\\client\\1.jpg")

	file, _ := os.Open("G:\\360Downloads\\code\\gocode\\codebak\\elastic_demo\\alisdk\\client\\1.jpg")
	defer file.Close()

	io.Copy(fileWriter, file)

	contentType := bodyWriter.FormDataContentType()
	bodyWriter.Close()
	fmt.Println(contentType)
	return bodyBuffer.String()
}

func createDrive() string {
	var driveId string
	createDriveRequest := new(client.CreateDriveRequest).
		SetDriveName("测试123").
		SetOwner("superadmin").
		SetTotalSize(100000000).
		SetDescription("测试234").
		SetDriveType("normal")
	cdrm := new(client.CreateDriveRequestModel).SetBody(createDriveRequest)
	response, err := ccpClient.CreateDrive(cdrm, runtime)
	if err != nil {
		fmt.Println(err.Error())
	}
	if response != nil {
		fmt.Println(response)
		driveId = *response.Body.DriveId
	}
	return driveId
}

func main() {
	//searcFile()
	//listFile()
	//filename := getDownloadUrl("5e7da59849795531cd6149f09329026d6afc6aa1")
	//ext := strings.Split(*filename,".")
	//fmt.Println(ext[len(ext)-1])
	//os.Exit(1)
	//httpup()
	//createFile()
	//createDrive()
	http.HandleFunc("/down", downloadFile)
	http.HandleFunc("/upload", uploadFile)
	err := http.ListenAndServe(":9000", nil)
	if err != nil {
		log.Fatal("ListenAndServer：", err)
	}
}
